from __future__ import absolute_import

if False:
    import unittest
    import sys
    import re
    import os
    import signal
    import os.path
    import argparse
    
    import forest.main
    from forest.tools.system.execute import poll, call
    from forest.config import Config
    
    class DummyArgs(object):
        debug = True
        wait = False
        verbose = True
        root = False
        build = 'build'
        list_tools = False
        list_commands = False
        
        def __init__(self, **entries): 
            self.__dict__.update(entries)
            
    #http://pguides.net/python-tutorial/python-timeout-a-function/
    #just the initial, simple approach, not copy-pasting the decorator
    #even when we get the console, usefull to test for a hang at boot, I think
    
    #ugly - state how long to wait for the installer to finish
    #booting, for collecting the boot input..
    BOOTTIME = 60
    
    class TimeoutException(Exception):
        pass
    
    import subprocess
    class TestInstallerBoot(unittest.TestCase):
        qemu_args = {
            '-hda': 'hda.img',
            #'-hdb': 'hdb.img',
            '-m': 2048,
            '-boot': 'd',
            '-cdrom': 'test.iso'
        }
        
        #@classmethod obligatory to have a single setup per class, I gather.
        #Attempting a setup per test, apart from horrible slowness of a 
        #rebuild per each test, also makes yum complain that the database 
        #is locked - not sure..
        @classmethod
        def setUpClass(cls):
            cls.prepare_headless_installer('tests/installer/test.tree')
            cls.prepare_disk_image(cls.qemu_args.get('-hda'))
            
            cls.setup_msgs()
    
        @classmethod
        def prepare_headless_installer(cls, treefile):
            config = Config(treefile, 'file://'+os.path.abspath(treefile))
            
            #config.set('installer.BuildInstallerImage.append', 'console=ttyS0')
            config.set('installer.BuildInstallerImage.destination', 'test.iso') 
            #config.set('installer.BuildInstallerImage.isolinuxcfg','tests/installer/isolinux.cfg')
            args = DummyArgs()
    
            forest.main.main(args, config)
            
        @staticmethod
        def prepare_disk_image(name, size='2G'):
            args_img = ['qemu-img', 'create', name, size]
            call(args_img)
    
        @classmethod
        def generate_qemu_headless_args(cls):
            args_qemu = ['qemu-kvm', '-nographic']
            
            for argname, val in cls.qemu_args.items():
                args_qemu.append(argname)
                args_qemu.append(str(val))
            return args_qemu
    
        @staticmethod
        def poll_process(args, shell=False):  
            # line buffered (default)
            #print args
            p = subprocess.Popen(args, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=shell, cwd=os.getcwd())
        
            while True:
                p.poll()
                line = p.stdout.readline()
                #eline = p.stderr.readline()
                if line:
                #    print 'in polling line :'
                #    print line
                    yield False, line
                # ERR: hmm, reading eline seems to break reading the rest of the command output
                #if eline:
                #    print 'an eline:'
                #    print eline
                #    yield True, eline
                if (line == "" and eline == "" and p.returncode is not None):
                    break
    
        @classmethod
        def setup_msgs(cls):
            def timeout_handler(signum, frame):
                raise TimeoutException()
                
            args = cls.generate_qemu_headless_args()
            cls.bootlog = []
            
            old_handler = signal.signal(signal.SIGALRM, timeout_handler)
            signal.alarm(BOOTTIME)
            
            try:
                for stderr, line in cls.poll_process(args):
                    if isinstance(line, basestring):
                        # a bit memory-wastefull
                        # but enables me to make separate test cases
                        # rather than one loop of regexes
                        # yet have them run the long build just once
                        cls.bootlog.append(line)
                        print line
            except TimeoutException:
                pass
            finally:
                signal.signal(signal.SIGALRM, old_handler)
                
            #in case it actually ends, cancel the alarm
            signal.alarm(0)
                        
    
        def msg_common(self, test_msg):
            pattern = re.compile(test_msg)
            
            found_a_msg = False      
            for line in self.bootlog:
                found_a_msg = pattern.match(line) is not None
                if found_a_msg:
                    break
    
            
            self.assertFalse(found_a_msg, msg='{} happened!'.format(test_msg))        
    
        def test_kernel(self):
            return self.msg_common('.*Kernel panic.*')
        
        def test_udev(self):
        # is it this
        # or 'Cannot add dependency job for unit udev.service, ignoring: 
        # Unit udev.service is masked.'
            return self.msg_common('.*Socket service udev\.service not loaded, refusing.')
        
        def test_sshd(self):
            return self.msg_common('.*sshd\.service entered failed state')
        
        def test_NetworkManager(self):
            return self.msg_common('.*NetworkManager\.service entered failed state')
        
        def test_dbus(self):
            return self.msg_common('.*dbus\.service entered failed state')
    
        @classmethod        
        def tearDownClass(cls):
            try:
                os.remove(cls.qemu_args.get('-hda',''))
                os.remove(cls.qemu_args.get('-cdrom',''))
            except OSError as e:
                pass
       
    
    if __name__ == '__main__':
        unittest.main()
